/**
 * Elite WebSocket CTIProxy Client
 * Created by Jeff on 2016/11/02.
 */
/*
let scpath = $SC.scpath;
let scfileext = $SC.scfileext || "";
let surl = "";
if (scpath) {
	surl = scpath + "/softphone.constants" + $E.jsv + scfileext;
} else {
	surl = $E.softphoneBasePath + "/softphone/softphone.constants" + $E.jsv;
}
define([$E.softphoneBasePath + "/softphone/softphone.constants" + $E.jsv], function($CTI_CONST){
 */
define(['./softphone.constants.min.js'], function($CTI_CONST){
	function commonreplace(template, args) {
		if (arguments.length > 1 && typeof arguments[0] === "string") {
			var result = arguments[0];
			if (arguments.length == 2 && typeof arguments[1] === "object") {
				var obj = arguments[1];
				for (let key in obj) {
					if (obj[key] != undefined) {
						let reg = new RegExp("({" + key + "})", "g");
						result = result.replace(reg, obj[key]);
					}
				}
			}
			/*
			else {
				for (var i = 1, len = arguments.length; i < len; i++) {
					if (arguments[i] != undefined) {
						// 这个在索引大于9时会有问题
						// var reg = new RegExp("({[" + (i - 1) + "]})", "g");
						// var reg = new RegExp("({)" + (i - 1) + "(})", "g");
						// result = result.replace(reg, arguments[i]);
					}
				}
			}
		  */
			return result;
		} else {
			return arguments[0];
		}
	}

	var ELITEWSCTIClient = {
		createNew: function(){
			var m_timer_login = 0;
			var m_request_comments = "";

			var softphone={};
			softphone.ctirefid = 0;
			softphone.rqqueue = {};
			softphone.dn = "";
			softphone.registreddn = "";
			softphone.agentid = "";
			softphone.agentpassword = "";
			softphone.agentgroup = "";

			m_Calllist = {};
			//CompleteTransferWhenDialing, CompleteTransferWhenNR, CompleteTransferWhenRB, CompleteTransferWhenEstablish, and same for CompleteConference
			f_autocomplete = "";
			conn_autocomplete = "";
			f_clearcalls = 0;
			f_errorclearcalls = false;

			var keyvaluesplit = "=";
			var cfg = {};

			var Error = function (error, args) {
				return this.init(error, args);
			};
			Error.UNKNOW_ERROR = {
				code: 80000,
				name: "UNKNOW_ERROR",
				message: $SC.lang("common.err.unknown", "未知错误")
			};
			Error.INVOKE_TIMEOUT = {
				code: 80100,
				name: "INVOKE_TIMEOUT",
				message: $SC.lang("common.err.requesttimeout", "请求超时") + "- {method}"
			};
			Error.REQUEST_FAIL_CTIMSG = {
				code: 80101,
				name: "REQUEST_FAIL_CTIMSG",
				message: $SC.lang("common.err.requestfail",  "请求失败") + " - {method}, " + $SC.lang("common.err.errorcodeplus", "失败代码：") + "{errorcode}",
				data: "{data}"
			}
			Error.NO_DEVICE_INFO = {
				code: 80110,
				name: "NO_DEVICE_INFO",
				message: $SC.lang("common.err.nodeviceinfo", "未获取到分机信息")
			};
			Error.INVALID_DEVICE_ID = {
				code: 80111,
				name: "INVALID_DEVICE_ID",
				message: $SC.lang("common.err.invaliddeviceplus", "无效的分机号：") + "{deviceId}"
			};
			Error.EXIST_DEVICE_LOGIN = {
				code: 80112,
				name: "EXIST_DEVICE_LOGIN",
				message: $SC.lang("common.err.existdeviceloginplus", "分机已登录，登录工号：") + "{agentId}"
			};
			Error.RESOURCE_BUSY = {
				code: 80113,
				name: "RESOURCE_BUSY",
				message: $SC.lang("common.err.devicebusy", "分机正在通话")
			};
			Error.INVALID_AGENT_ID = {
				code: 80121,
				name: "INVALID_AGENT_ID",
				message: $SC.lang("common.err.invalidagentidplus", "无效的工号：") + "{agentId}"
			};
			Error.INVALID_PASSWORD = {
				code: 80122,
				name: "INVALID_PASSWORD",
				message: $SC.lang("common.err.invalidpassword", "无效的密码")
			};
			Error.EXIST_AGENT_LOGIN = {
				code: 80123,
				name: "EXIST_AGENT_LOGIN",
				message: $SC.lang("common.err.existagentloginplus","工号已登录，登录分机：") + "{deviceId}"
			};
			Error.INVALID_STATE_ERR = {
				code: 80201,
				name: "INVALID_STATE_ERR",
				message: $SC.lang("common.err.invalidstateerror", "无法完成此操作")
			}
			Error.prototype = {
				constructor: Error,
				init: function (error, args) {
					var newError = null;
					if (typeof error === "object") {
						if (typeof args !== 'undefined') {
							newError = Object.create(error);
							for (var name in newError) {
								newError[name] = commonreplace(newError[name], args);
							}
						} else {
							newError = error;
						}
					} else if (typeof error === "string") {
						newError = {
							code: 80999,
							name: "Error",
							message: error
						};
					}
					return newError;
				}
			};

			window.addEventListener("unhandledrejection", function(promiseRejectionEvent) {
				//$SC.addconsolelog(promiseRejectionEvent);

				var r = promiseRejectionEvent.reason;
				if (r.code && r.data && r.message) {
					softphone.onMessage(r.data);
					//12--INVALID_CSTA_DEVICE_IDENTIFIER
			    if ((r.code != 12) && (r.code == Error.REQUEST_FAIL_CTIMSG.code) && softphone.registereddn) {
						softphone.queryagentstate(softphone.dn, softphone.agentid, undefined, {timeout: 5000, internaluse: true})
							.then(function(e) {
								if (e.event.value == $CTI_CONST.CTI_MSG.EVT_AGENTLOGOUT) {
									$SC.addconsolelog('[wscti]internal queryagentstate got agentstate AgentLogout');
									softphone.closewebsocket('EVT_AGENTLOGOUT');
								}}, function(e) {
							});
					}
				}
			});

			softphone.commoncall = function(callname, callparas, callback) {
				switch (callname.toLowerCase()){
					case "deleteparty":
						return softphone.deleteparty(callparas);
						break;
					case "queryotheragent":
					case "queryotheragentstate":
						softphone.queryagentstate(softphone.dn, callparas.agentid, 1, {timeout: 5000, internaluse: true})
							.then(function(e) {
								if (callback) {
									if (e && e.agentstate) {
										callback(e);
									} else {
										callback(false);
									}
								}
								}, function(e) {
									$SC.addconsolelog('[wscti]internal queryagentstate fail', e);
									if (callback) {
										callback(false);
									}
							})
						break;
					default:
						softphone.logmsg("unsupported commoncall " + callname);
						break;
				}
			};

			softphone.connectserver = function(serverendpoint, onOpen,onClose,onMessage,onError,onSendMessage){
				try {
					if (softphone.websocket) {
						softphone.websocket.onclose = undefined;
						softphone.websocket.onmessage = undefined;
						softphone.websocket.onerror = undefined;
						//softphone.websocket.close();
						softphone.closewebsocket('connectserver');
					}

					softphone.websocket = new WebSocket(serverendpoint);
					$SC.addconsolelog('[wscti]websocket init: ' + softphone.websocket.url);
					softphone.websocket.onopen = function(evt){
						softphone.registereddn = '';
						onOpen(evt);
					}
					softphone.websocket.onclose = function(evt){
						softphone.registereddn = '';
						$SC.addconsolelog('[wscti]websocket closed');
						if (m_timer_login) {
							clearInterval(m_timer_login);
							m_timer_login = 0;
						}
						onClose(evt);
					}
					softphone.websocket.onmessage = function(evt){
						var opt = {};
						_onmessage(evt, opt);
						//$SC.onCTIEvent(evt);
						//onMessage.apply(this, arguments);
						if (opt && opt.ignoreit) {
							return;
						}
						if (evt.data2) {
							if (evt.data2.internaluse) {
							} else {
								//onMessage(evt.data2);
								onMessage(evt);
							}
						} else {
							onMessage(evt);
						}
						if ($SC.CallInfo.CallState2 == 0) {
							//f_clearcalls = false;
							m_Calllist = {};
						}
					}
					softphone.websocket.onerror = function(evt){
						onError(evt);
					}

					softphone.onMessage = onMessage;

					softphone.OnSendMessage = function(evt){
						onSendMessage(evt);
					}
					keyvaluesplit = $SC._getconfig('CTI', 'KeyValueSplit') || '=';
					cfg.mutetransfer = $SC._getconfig('CTI', 'mutetransfer');
				} catch (err) {
					softphone.logmsg('connectserver error: code = ' + err.code + ', message = ' + err.message);
				}
			};

			//REQ_INITIALIZEADS = 80,
			//REQ_OPENSERVER = 81,
			//REQ_REGISTERAGENT = 83,
			//REQ_UNREGISTERADDRESS = 88,
			//REQ_SINGLESTEPTRANSFER = 100,
			//REQ_SINGLESTEPCONFERENCE = 101,
			//REQ_CLOSESERVER = 102,
			//REQ_SWAPHOLD = 103,
			//REQ_STARTRECORD = 104,
      //REQ_STOPRECORD = 105,
      //REQ_SETOHHOOK = 106,
      //REQ_REPORTAGENTID = 107,
      //REQ_STARTPLAY = 108,
      //REQ_STOPPLAY = 109,
      //REQ_MUTE = 110,
      //REQ_UNMUTE = 111,
      //REQ_INTERCEPT = 112,
      //REQ_FORCEHANGUP = 113,
      //REQ_FORCEDISCONNECTAGENTBYDN = 114,
      //REQ_SENDDTMF = 115,
      //REQ_LISTEN = 116,
      //REQ_BARGEIN = 117,
      //REQ_GETCURRENTAGENT = 118,
      //REQ_GETCURRENTAGENTSTATE = 119,
      //REQ_GETQUEUEINFO = 120,
      //REQ_DEFLECTCALL = 121,
      //REQ_SETNIGHTRING = 122,
      //REQ_ESCAPESERVICE = 123,
      //REQ_GETDTMF = 124,
      //REQ_SENDIVRMESSAGE = 125,
      //REQ_FORCEAGENTNOTREADY = 126,
      //REQ_FORCEAGENTREADY = 127,
      //REQ_FORCEAGENTLOGOUT = 128,
      //REQ_PLAYTTS = 129,
      //REQ_FORCETAKEOVER = 130,
      //REQ_TRANSFERTOIVRANDWAITBACK = 131,
      //REQ_APCPLAYFASTFORWARD = 132,
      //REQ_APCPLAYFASTBACKWARD = 133,
      //REQ_QUERYAGENTSTATE = 134,
      //REQ_QUERYAGENTGROUPSTATE = 135,
      //REQ_COMMONCALL = 136,
      //REQ_WRAPUPENDED = 137,
      //REQ_COACH = 138,
      //REQ_FORWARDCALL = 139,
      //REQ_SNAPSHOTDEVICE = 140,
      //REQ_SNAPSHOTCALL = 141,
      //REQ_RESETAGENTSKILL = 142,
			//REQ_DELETEPARTY = 143,
	    //REQ_MAX = 144

			//REQ_REGISTERADDRESS = 82
			softphone.registerdn = function(dn)
			{
				if (softphone.registereddn && softphone.registereddn !== dn) {
					softphone.unregisterdn(softphone.registereddn);
				}
				this.dn = dn;
				const jsonobj = {
					request: {type: 1, value: 82},
					regmode: {type: 1, value: 1},
					dn: {type: 3, value: dn},
					token: {type: 3, value: $E.getActiveProject().token},
					ds: {type: 3, value: $E.dataService.key}
				};
				const method = 'registerdn';
				const options = {
					timeout: 5000,
					succevents: [16],
					timeoutfunc: function(){
						softphone.closewebsocket('registerdn timeout');
					}
				}
				softphone.websocketsend(jsonobj, method, options);
			};

			softphone.unregisterdn = function(dn) {
				softphone.websocketsend({
					request: {type: 1, value: 88},
					dn: {type: 3, value: dn}
				})
			};

			//REQ_SETAGENTLOGIN = 84
			softphone.login = function(agentid,dn,agentpassword,agentgroup,workmode,acdagent) {
				this.agentid = agentid;
				this.dn = dn;
				this.agentpassword = agentpassword;
				this.agentgroup = agentgroup;
				softphone.snapshotdevice(dn, {timeout: 5000, internaluse: true})
					.then(function(e) {
						if ($SC._getconfig('CTI', 'queryextension') == '0') {

						} else {
							if (e && e.callcount && e.callcount.value > 0) {
								err = new Error(Error.RESOURCE_BUSY);
								softphone.InternalOnError(err.message, err.code, err.name);
								return;
							}
						}
						if ($SC._getconfig('CTI', 'queryagent') == '0') {
							$SC.addconsolelog('[wscti]no queryagent and login directly');
							softphone.agentlogin(agentid, dn, agentpassword, agentgroup, workmode, acdagent);
							return;
						} //else {
						softphone.getcurrentagent(dn, agentid, {timeout: 5000, internaluse: true})
							.then(function(e) {
								if (e.otherdn && e.otherdn.value && e.otherdn.value != dn) {
									err = new Error(Error.EXIST_AGENT_LOGIN, {deviceId: e.otherdn.value});
									softphone.InternalOnError(err.message, err.code, err.name);
									return;
								}
								softphone.getcurrentagent(dn, undefined, {timeout: 5000, internaluse: true})
									.then (function(e) {
										if (e.agentid) {
											if (e.agentid.value && e.agentid.value != agentid) {
												err = new Error(Error.EXIST_DEVICE_LOGIN, {agentId: e.agentid.value});
												softphone.InternalOnError(err.message, err.code, err.name);
												return;
											} else if (e.agentid.value == agentid){
												softphone.agentlogout(agentid, agentgroup, dn, {timeout: 5000, internaluse: true, succevents: [71]})
													.then (function(e) {
														softphone.agentlogin(agentid, dn, agentpassword, agentgroup, workmode, acdagent);
														}, function(e) {
														softphone.onMessage(e);
													});
											} else {
												softphone.agentlogin(agentid, dn, agentpassword, agentgroup, workmode, acdagent);
											}
										} else {
											softphone.agentlogin(agentid, dn, agentpassword, agentgroup, workmode, acdagent);
										}
										}, function(e) {
										softphone.onMessage(e);
									});
								}, function(e) {
								try {
									var datas = JSON.parse(e.data);
									var errcode;
									if (datas && datas.errorcode) {
										errcode = datas.errorcode.value;
									}
									if (errcode == 3 || errcode == 12) {
										err = new Error(Error.INVALID_AGENT_ID, {agentId: agentid});
										softphone.InternalOnError(err.message, err.code, err.name);
										return;
									} else {
										softphone.InternalOnError(e.message, e.code, e.name);
									}
								} catch(err) {
									$SC.addconsolelog('[wscti]query agent failed, ignore it and login directly');
									softphone.agentlogin(agentid, dn, agentpassword, agentgroup, workmode, acdagent);
								}
							});
						}, function(e) {
						softphone.InternalOnError(e.message, e.code, e.name);
					});
			};

			softphone.agentlogin = function(agentid, dn, agentpassword, agentgroup, workmode, acdagent, options) {
				return softphone.websocketsend({
					request: {type: 1, value: 84},
					agentid: {type: 3, value: agentid},
					password: {type: 3, value: agentpassword},
					agentgroup: {type: 3, value: agentgroup},
					dn: {type: 3, value: dn},
					acdagent: {type: 1, value: acdagent},
					workmode: {type: 1, value: workmode}
				}, 'login', options);
			};

			//REQ_SETAGENTLOGOUT = 87
			softphone.agentlogout = function(agentid, agentgroup, dn, options){
	      if (!agentid) {
	        agentid = this.agentid;
	      }
	      if (!agentgroup) {
	        agentgroup = this.agentgroup;
	      }
	      if (!dn) {
	        dn = this.dn;
	      }
	      if (!options) {
	        options = {timeout : 5000, succevents: [71], failevents: [11]};
	      }
	      return softphone.websocketsend({
	        request: {type: 1, value: 87},
	        agentid: {type: 3, value: agentid},
	        agentgroup: {type: 3, value: agentgroup},
	        dn: {type: 3, value: dn}
	      }, 'agentlogout', options);
	    };

			//REQ_SETAGENTNOTREADY = 86
			softphone.agentnotready = function(workmode){
	      if (workmode == 4) {
	        return softphone.acw();
	      }
	      softphone.websocketsend({
	        request: {type: 1, value: "86"},
	        dn: {type: 3, value: this.dn},
	        workmode: {type: 1, value: workmode},
	        agentid: {type: 3, value: this.agentid},
	        password: {type: 3, value: this.agentpassword},
	        agentgroup: {type: 3, value: this.agentgroup}
	      }, 'agentnotready', {timeout : 5000, succevents: [73]});
	    };

			softphone.aux = function(reasoncode) {
	      softphone.websocketsend({
	        request: {type: 1, value: 86},
	        dn: {type: 3, value: this.dn},
	        workmode: {type: 1, value: 3},
	        reasoncode: {type: 1, value: reasoncode},
	        agentid: {type: 3, value: this.agentid},
	        password: {type: 3, value: this.agentpassword},
	        agentgroup: {type: 3, value: this.agentgroup}
	      }, 'aux', {timeout : 5000, succevents: [73]});
	    };

			softphone.acw = function() {
	      softphone.websocketsend({
	        request: {type: 1, value: "86"},
	        dn: {type: 3, value: this.dn},
	        workmode: {type: 1, value: 4},
	        agentid: {type: 3, value: this.agentid},
	        password: {type: 3, value: this.agentpassword},
	        agentgroup: {type: 3, value: this.agentgroup}
	      }, 'acw', {timeout : 5000, succevents: [73]});
	    };

			//REQ_SETAGENTREADY = 85
      softphone.agentready = function(workmode) {
	      softphone.websocketsend({
	        request: {type: 1, value: 85},
	        dn: {type: 3, value: this.dn},
	        workmode: {type: 1, value: workmode || 0},
	        agentid: {type: 3, value: this.agentid},
	        password: {type: 3, value: this.agentpassword},
	        agentgroup: {type: 3, value: this.agentgroup}
	      }, 'agentready', {timeout : 5000, succevents: [72]});
	    };

			//REQ_MAKECALL = 90,
			softphone.makecall = function(dest, userDatas, callback) {
				if (f_clearcalls) {
					$SC.addconsolelog("[wscti]clear f_clearcalls from " + f_clearcalls + " by makecall");
					f_clearcalls = 0;
				}
	      let requestJSON = {
	        request: {type: 1, value: '90'},
	        dn: {type: 3, value: this.dn},
	        dest: {type: 3, value: dest},
	        site: {type: 3, value: ''}
	      };
	      if (userDatas) {
	        requestJSON.userdata = {type:5, value: userdata2metauserdata(userDatas)};
	      }
	      softphone.websocketsend(requestJSON, 'makecall');
	    };

			//REQ_RELEASECALL = 91,
			softphone.releasecall = function(callid) {
	      var id="";
	      if(callid){
	        id=callid;
	      }

	      if(id!=""){
	        if (m_Calllist[id] && m_Calllist[id].event && m_Calllist[id].event.value == $CTI_CONST.CTI_MSG.EVT_HELD) {
	          $SC.addconsolelog('[wscti]retrievecall before releasecall(' + callid + ')');
	          m_request_comments = 'retrievecall before releasecall';
	          softphone.retrievecall(callid);
	        }

	        softphone.websocketsend({
	          request: {type: 1, value: 91},
	          dn: {type: 3, value: this.dn},
	          connectionid: {type: 3, value: id}
	        }, 'releasecall');
		    } else {
		      var error = new Error(Error.INVALID_STATE_ERR, {

		      });
		      softphone.InternalOnError(error.message, error.code, error.name);
		    }
	    };

			softphone.clearcalls = function() {
	      var cid = '';

        for (var x in m_Calllist) {
          cid = '';
          if (m_Calllist[x].connectionid) {
            cid = m_Calllist[x].connectionid.value;
          } else if (m_Calllist[x].callid) {
            cid = m_Calllist[x].callid.value;
          }
          if (cid) {
            $SC.addconsolelog("[wscti]releasecall(" + cid + ")");
            softphone.releasecall(cid);
          }
        }
      };

			//REQ_ANSWERCALL = 89,
			softphone.answercall = function(callid) {
	      var id="";
	      if(callid){
	        id=callid;
	      }
	      if(id!=""){
		      softphone.websocketsend({
	          request: {type: 1, value: 89},
	          dn: {type: 3, value: this.dn},
	          connectionid : {type: 3, value: id}
	        }, 'answercall')
		    } else {
		      var error = new Error(Error.INVALID_STATE_ERR, {

		      });
		      softphone.InternalOnError(error.message, error.code, error.name);
		    }
	    };

			//REQ_HOLDCALL = 92
			softphone.holdcall = function(callid, params) {
	      var id="";
	      if(callid){
	        id=callid;
	      }
	      var jsonrequest = {
					request: {type: 1, value: 92},
					dn: {type: 3, value: this.dn},
					connectionid : {type: 3, value: id}
				}
		      if (params && params.holdsilence == 1) {
		        jsonrequest.holdsilence = {type : 1, value : 1};
				};
	      if(id!=""){
		      softphone.websocketsend(jsonrequest, 'holdcall')
		    } else {
		      var error = new Error(Error.INVALID_STATE_ERR, {

		      });
		      softphone.InternalOnError(error.message, error.code, error.name);
		    }
	    };

			//REQ_RETRIEVECALL = 93,
			softphone.retrievecall = function(callid) {
	      var id="";
	      if(callid){
	        id=callid;
	      }
	      if(id!=""){
		      softphone.websocketsend({
	          request: {type: 1, value: 93},
	          dn: {type: 3, value: this.dn},
	          connectionid : {type: 3, value: id}
	        }, 'retrievecall')
		    } else {
		      var error = new Error(Error.INVALID_STATE_ERR, {

		      });
		      softphone.InternalOnError(error.message, error.code, error.name);
		    }
	    };

			//REQ_INITTRANSFER = 94,
			softphone.inittransfer = function(callid, dest, userdatas) {
	      var id="";
	      if(callid){
	        id=callid;
	      }
	      if(id!=""){
	        f_autocomplete = '';
	        conn_autocomplete = callid;

		      var request='{"request":{"type":1,"value":"94"},"dn":{"type":3,"value":"'+this.dn+'"},"connectionid":{"type":3,"value":"'+id+'"},"dest":{"type":3,"value":"'+dest+'"},"site":{"type":3,"value":""}';
		      if(userdatas){
		        userdatas = userdata2metauserdata(userdatas);
		        if (getuserdatabykey(userdatas, 'AutoComplete')){
		          f_autocomplete = 'completetransferwhendialing';
		          removeuserdatabykey(userdatas, 'AutoComplete');
		        }
		        if (getuserdatabykey(userdatas, 'CompleteTransferWhenDialing')) {
		          f_autocomplete = 'completetransferwhendialing';
		          removeuserdatabykey(userdatas, 'CompleteTransferWhenDialing');
		        }
		        if (getuserdatabykey(userdatas, 'CompleteTransfereWhenNR')) {
		          f_autocomplete = 'completetransferwhennr';
		          removeuserdatabykey(userdatas, 'CompleteTransferWhenNR');
		        }
		        if (getuserdatabykey(userdatas, 'CompleteTransferWhenRB')) {
		          f_autocomplete = 'completetransferwhenrb';
		          removeuserdatabykey(userdatas, 'CompleteTransferWhenRB');
		        }
		        if (getuserdatabykey(userdatas, 'CompleteTransferWhenEstablish')) {
		          f_autocomplete = 'completetransferwhenestablish';
		          removeuserdatabykey(userdatas, 'CompleteTransferWhenEstablish');
		        }
		        if (getuserdatabykey(userdatas, 'CompleteWhenDialing')) {
		          f_autocomplete = 'completetransferwhendialing';
		          removeuserdatabykey(userdatas, 'CompleteWhenDialing');
		        }
		        if (getuserdatabykey(userdatas, 'CompleteWhenNR')) {
		          f_autocomplete = 'completetransferwhennr';
		          removeuserdatabykey(userdatas, 'CompleteWhenNR');
		        }
		        if (getuserdatabykey(userdatas, 'CompleteWhenRB')) {
		          if (!f_autocomplete) {
							f_autocomplete = 'completetransferwhenrb';
						}
		          removeuserdatabykey(userdatas, 'CompleteWhenRB');
		        }
		        if (getuserdatabykey(userdatas, 'CompleteWhenEstablish')) {
		          f_autocomplete = 'completetransferwhenestablish';
		          removeuserdatabykey(userdatas, 'CompleteWhenEstablish');
		        }
		        userdatas = checkuudata(userdatas);
		        if (typeof(userdatas)=='object') {
		          userdatas = JSON.stringify(userdatas);
		        }
		        request+=',"userdata":{"value":'+userdatas+',"type":5}';
		      }
		      request+='}';
		      if (f_autocomplete) {
		        softphone.logmsg("f_autocomplete="+f_autocomplete+",conn_autocomplete="+conn_autocomplete);
		      }
		      //this.websocket.send(request);
		      //this.OnSendMessage(request);
				softphone.websocketsend(request, "inittransfer");
		    }
	    };

			//REQ_SINGLESTEPCONFERENCE = 101
			softphone.singlestepconference = function(callid, dest, userdatas)
			{
				var request = {"request" : {"type" : 1, "value" : "101"},
					"dn" : {"type" :3, "value" : this.dn},
					"connectionid" : {"type" : 3, "value" : callid},
					"dest" : {"type" : 3, "value" : dest}
				}
				if (userdatas) {
					userdatas = userdata2metauserdata(userdatas);
					userdatas = checkuudata(userdatas);
					request.userdata = {"type" : 5, "value" : userdatas};
				}
				softphone.websocketsend(request, "singlestepconference");
			}

			//REQ_INITCONFERENCE = 95,
			softphone.initconference = function(callid, dest, userdatas) {
	      var id="";
	      if(callid){
	        id=callid;
	      }
	      if(id!=""){
	        f_autocomplete = '';
	        conn_autocomplete = callid;

	        var request='{"request":{"type":1,"value":"95"},"dn":{"type":3,"value":"'+this.dn+'"},"connectionid":{"type":3,"value":"'+id+'"},"dest":{"type":3,"value":"'+dest+'"},"site":{"type":3,"value":""}';
		      if(userdatas){
		        userdatas = userdata2metauserdata(userdatas);
		        if (getuserdatabykey(userdatas, 'AutoComplete')){
		          f_autocomplete = 'completeconferencewhendialing';
		          removeuserdatabykey(userdatas, 'AutoComplete');
		        }
		        if (getuserdatabykey(userdatas, 'CompleteConferenceWhenDialing')) {
		          f_autocomplete = 'completeconferencewhendialing';
		          removeuserdatabykey(userdatas, 'CompleteConferenceWhenDialing');
		        }
		        if (getuserdatabykey(userdatas, 'CompleteConferenceWhenNR')) {
		          f_autocomplete = 'completeconferencewhennr';
		          removeuserdatabykey(userdatas, 'CompleteConferenceWhenNR');
		        }
		        if (getuserdatabykey(userdatas, 'CompleteConferenceWhenRB')) {
		          f_autocomplete = 'completeconferencewhenrb';
		          removeuserdatabykey(userdatas, 'CompleteConferenceWhenRB');
		        }
		        if (getuserdatabykey(userdatas, 'CompleteConferenceWhenEstablish')) {
		          f_autocomplete = 'completeconferencewhenestablish';
		          removeuserdatabykey(userdatas, 'CompleteConferenceWhenEstablish');
		        }
		        if (getuserdatabykey(userdatas, 'CompleteWhenDialing')) {
		          f_autocomplete = 'completeconferencewhendialing';
		          removeuserdatabykey(userdatas, 'CompleteWhenDialing');
		        }
		        if (getuserdatabykey(userdatas, 'CompleteWhenNR')) {
		          f_autocomplete = 'completeconferencewhennr';
		          removeuserdatabykey(userdatas, 'CompleteWhenNR');
		        }
		        if (getuserdatabykey(userdatas, 'CompleteWhenRB')) {
		          f_autocomplete = 'completeconferencewhenrb';
		          removeuserdatabykey(userdatas, 'CompleteWhenRB');
		        }
		        if (getuserdatabykey(userdatas, 'CompleteWhenEstablish')) {
		          f_autocomplete = 'completeconferencewhenestablish';
		          removeuserdatabykey(userdatas, 'CompleteWhenEstablish');
		        }
		        //request+=',"userdata":'+userdatas;
		        userdatas = checkuudata(userdatas);
		        if (typeof(userdatas)=='object') {
		          userdatas = JSON.stringify(userdatas);
		        }
		        request+=',"userdata":{"value":'+userdatas+',"type":5}';
		      }
		      request+='}';
		      //this.websocket.send(request);
		      //this.OnSendMessage(request);
				softphone.websocketsend(request, "initconference");
		    }
	    };

			//REQ_COMPLETETRANSFER = 96,
			softphone.completetransfer = function(callid, prevcallid) {
	      var id="", previd="";
	      if(callid){
	        id=callid;
	      }
	      if(prevcallid){
	        previd=prevcallid;
	      }
	      if(id!=""&&previd!=""){
		      var request='{"request":{"type":1,"value":"96"},"dn":{"type":3,"value":"'+this.dn+'"},"activecallid":{"type":3,"value":"'+id+'"},"heldcallid":{"type":3,"value":"'+previd+'"}';
		      request+='}';
		      //this.websocket.send(request);
		      //this.OnSendMessage(request);
				softphone.websocketsend(request, "completetransfer");
		    }
	    };

			//REQ_COMPLETECONFERENCE = 97,
			softphone.completeconference = function(callid, prevcallid) {
	      var id="", previd="";
	      if(callid){
	        id=callid;
	      }
	      if(prevcallid){
	        previd=prevcallid;
	      }
	      if(id!=""&&previd!=""){
		      //var request='{"request":{"type":1,"value":"97"},"dn":{"type":3,"value":"'+this.dn+'"},"activecallid":{"type":3,"value":"'+id+'"},"heldcallid":{"type":3,"value":"'+previd+'"}';
		      //request+='}';
		      //this.websocket.send(request);
		      //this.OnSendMessage(request);
	        softphone.websocketsend({
	          request: {type: 1, value: 97},
	          dn: {type: 3, value: this.dn},
	          activecallid: {type: 3, value: id},
	          heldcallid: {type: 3, value: previd}
	        }, 'completeconference');
		    } else {
		      var error = new Error(Error.INVALID_STATE_ERR, {

		      });
		      softphone.InternalOnError(error.message, error.code, error.name);
		    }
	    };

			//REQ_RECONNECT = 99,
			softphone.reconnect = function(callid,prevcallid) {
	      var id="", previd="";
	      if(callid){
	        id=callid;
	      }
	      if(prevcallid){
	        previd=prevcallid;
	      }
	      if(id!=""&&previd!=""){
		      var request='{"request":{"type":1,"value":"99"},"dn":{"type":3,"value":"'+this.dn+'"},"activecallid":{"type":3,"value":"'+id+'"},"heldcallid":{"type":3,"value":"'+previd+'"}';
		      request+='}';
		      //this.websocket.send(request);
		      //this.OnSendMessage(request);
				softphone.websocketsend(request, "reconnect");
		    } else {
		      var error = new Error(Error.INVALID_STATE_ERR, {

		      });
		      softphone.InternalOnError(error.message, error.code, error.name);
		    }
	    };

			//REQ_MUTETRANSFER = 98,
			softphone.mutetransfer = function(callid, dest, userdatas) {
				if (cfg.mutetransfer == 1) {
					var request='{"request":{"type":1,"value":"98"},"dn":{"type":3,"value":"'+this.dn+'"},"connectionid":{"type":3,"value":"'+callid+'"},"dest":{"type":3,"value":"'+dest+'"},"site":{"type":3,"value":""}';
					if(userdatas){
						userdatas = checkuudata(userdatas);
						if (typeof(userdatas)=='object') {
							userdatas = JSON.stringify(userdatas);
						}
						request+=',"userdata":{"value":'+userdatas+',"type":5}';
					}
					request+='}';
					softphone.websocketsend(request, "mutetransfer");
					return true;
				}

	      userdatas = adduserdata(userdatas, 'CompleteWhenRB', 3, '1');
	      f_clearcalls = 2;   //expect for 2 evt_released
				$SC.addconsolelog("[wscti]set f_clearcalls = 2 in mutetransfer");
		    softphone.inittransfer(callid, dest, userdatas);
		    var t = setTimeout(function(){
		      if (f_clearcalls) {
		          if ($SC.CallInfo.CallState2 > 0) {
                            $SC.addconsolelog("[wscti]in mutetransfer timedout, clearcalls and clear f_clearcalls from " + f_clearcalls);
                            f_clearcalls = 0;
                            m_request_comments = 'clearcalls() for mutetransfer timeout';
                            softphone.clearcalls();
                        } else {
                            $SC.addconsolelog("[wscti]clear f_clearcalls from " + f_clearcalls + " by timeout");
                        }
		      }
		    }, 3000);
	    };

			softphone.senddtmf = function(dtmf) {
        var conn = '';

        for (var x in m_Calllist) {
          if (m_Calllist[x].connectionid) {
            conn = m_Calllist[x].connectionid.value;
          } else if (m_Calllist[x].callid) {
            conn = m_Calllist[x].callid.value;
          }
          if (m_Calllist[x].event) {
            if (m_Calllist[x].event.value == $CTI_CONST.CTI_MSG.EVT_ESTABLISH) {
              break;
            }
          }
        }
        if (conn) {
          var request={
              "request": {"type":1, "value": "115"},
              "dn": {"type": 3, "value": this.dn},
              "callid": {"type": 3, "value": conn},
              "dtmf": {"type": 3, "value": dtmf}
          };
          softphone.websocketsend(request, 'senddtmf');
          return true;
        } else {
          softphone.logmsg('senddtmf got no connectionid');
          return false;
        }
	    };

			//REQ_DELETEPARTY = 143
			softphone.deleteparty = function(dn) {
				var call = $SC.CallInfo.getActiveCall();
				if (!call) {
					softphone.logmsg("deleteparty is ignored, for no activecall");
				}
				var request = {
					"request": {"type": 1, "value": "143"},
					"dn": {"type": 3, "value": this.dn},
					"callid": {"type": 3, "value": call.connectionid},
					"party": {"type": 3, "value": dn}
				};
				softphone.websocketsend(request, 'deleteparty');
				return true;
			};

			//REQ_LISTEN = 116，监听
			softphone.listen = function(dn, agentid) {
				var request = {
					"request": {"type": 1, "value": "116"},
					"dn": {"type": 3, "value": this.dn},
					"dest": {"type": 3, "value": dn}
				}
				softphone.websocketsend(request, 'listen');
				return true;
			};

			//REQ_BARGEIN = 117，插入
			softphone.bargein = function(dn, agentid) {
				var request = {
					"request": {"type": 1, "value": "117"},
					"dn": {"type": 3, "value": this.dn},
					"dest": {"type": 3, "value": dn}
				}
				softphone.websocketsend(request, 'bargein');
				return true;
			};

			//REQ_INTERCEPT = 112, 接管/强拆
			softphone.intercept = function(dn, agentid) {
				//console.log("[softphone_wscti]unsupported request intercept");
				//return false;
				var request = {
					request: {type: 1, value: 112},
					dn: {type: 3, value: this.dn},
					dest: {type: 3, value: dn}
				}
				softphone.websocketsend(request, 'intercept');
				return true;
			};

			//REQ_COACH = 138，教练/密语
			softphone.coach = function(dn, agentid) {
				var request = {
					"request": {"type": 1, "value": "138"},
					"dn": {"type": 3, "value": this.dn},
					"dest": {"type": 3, "value": dn}
				};
				softphone.websocketsend(request, 'coach');
				return true;
			};

			//REQ_FORCEAGENTLOGOUT = 128
			softphone.forceagentlogout = function(dn, agentid) {
				var request = {
					"request": {"type": 1, "value": "128"},
					"dn": {"type": 3, "value": this.dn},
					"agentid": {"type": 3, "value": agentid}
				};
				softphone.websocketsend(request, 'forceagentlogout');
				return true;
			};

			//REQ_FORCEAGENTREADY = 127
			softphone.forceagentready = function(dn, agentid, callback) {
				let request = {
					"request": {"type": 1, "value": "127"},
					"dn": {"type": 3, "value": this.dn},
					"agentid": {"type": 3, "value": agentid}
				};
				softphone.websocketsend(request, 'forceagentready');
				return true;
			};

			//REQ_FORCEAGENTNOTREADY = 126
			softphone.forceagentnotready = function(dn, agentid, callback) {
				var request = {
					"request": {"type": 1, "value": "126"},
					"dn": {"type": 3, "value": this.dn},
					"agentid": {"type": 3, "value": agentid}
				};
				softphone.websocketsend(request, 'forceagentnotready');
				return true;
			};

			softphone.forceDisconnectAgentByDN = function(dn, agentid, callback) {
				var request = {
					request: {type: 1, value: 114},
					dn: {type: 3, value: this.dn},
					dest: {type: 3, value: dn}
				};
				softphone.websocketsend(request, "forceDisconnectAgentByDN");
				return true;
			};

			softphone.keepalive = function() {
				var request = {
					"request": {"type": 1, "value": "0"},
					"dn": {"type":3, "value": this.dn}
				};
				this.websocket.send(request);
			};

			//REQ_SNAPSHOTDEVICE = 140,
			softphone.snapshotdevice = function(dn, options) {
				if ($SC._getconfig('CTI', 'snapshotdevice') == '0') {
					var promise = new Promise(function(resolve, reject) {
						setTimeout(function() {
							resolve({'fake': 1, 'callcount': 0});
						}, 10);
					});
					return promise;
				}

	      if (options && !options.succevents) {
	        options.succevents = [27]
	      }
	      return softphone.websocketsend({
	        request: {type: 1, value: 140},
	        dn: {type: 3, value: dn}
	      }, 'snapshotdevice', options);
	    };

			//REQ_SNAPSHOTCALL = 141
			softphone.snapshotcall = function(dn, options) {
	      return softphone.websocketsend({
	        request : {type:1 ,value :141},
	        dn: {type: 3, value: dn}
	      }, 'snapshotcall', options)
	    };

			//REQ_QUERYAGENTSTATE = 134,
			softphone.queryagentstate = function(dn, agentid, otheragent, options) {
	      return softphone.websocketsend({
	        request: {type: 1, value: 134},
	        dn: {type: 3, value: dn},
	        agentid: {type: 3, value: agentid},
	        otheragent: {type: 1, value: otheragent}
	      }, 'queryagentstate', options);
	    };

			//REQ_GETCURRENTAGENT = 118
			softphone.getcurrentagent = function(dn, otheragentid, options) {
				if ($SC._getconfig("CTI", "getcurrentagent") == "0") {
					var promise = new Promise(function(resolve, reject) {
						setTimeout(function() {
							resolve({'fake': 1});
						}, 10);
					});
					return promise;
				}

	      var req = {request: {type: 1, value: 118}, dn: {type: 3, value: dn}};
	      if (otheragentid) {
	        req.OtherAgent = {type: 3, value: otheragentid};
	      }
	      return softphone.websocketsend(req, 'getcurrentagent', options);
	    };

			softphone.InternalOnError = function(errMessage, errorCode, errorName) {
				var ret = {};
				ret.event = {type: 1, value: $CTI_CONST.CTI_MSG.EVT_ERROR};
        ret.dn = {type: 3, value: this.dn};
        //ret.channelid = this.channelid;
        if (!errorCode) {
          errorCode = 80001
        }
        ret.errorcode = {type: 3, value: errorCode};
        ret.errordesc = {type: 3, value: errMessage};
        if (errorName) {
          ret.errorname = {type: 3, value: errorName};
        }
        softphone.onMessage(JSON.stringify(ret));
			};

			softphone.closewebsocket = function(sfor) {
				try{
					if (softphone.websocket) {
						softphone.logmsg('softphone.websocket.close(), readyState = ' + softphone.websocket.readyState + ', ' + sfor);
						if (softphone.websocket.readyState !== 3) {
							softphone.websocket.close();
						}
					} else {

					}
				} catch (e) {

				}
			};

			softphone.websocketsend = function(jsonobj, method, options) {
		    softphone.ctirefid++;
		    if (typeof(jsonobj) == 'string') {
		      jsonobj = JSON.parse(jsonobj);
				}
				jsonobj.CTIRefID = {type: 3, value: softphone.ctirefid};

				let request = JSON.stringify(jsonobj);

		    if (m_request_comments) {
		      request = JSON.parse(request);
		      request.comments = m_request_comments;
		      request = JSON.stringify(request);
		      m_request_comments = "";
				}

		    if (options) {
				  let timeout = options.timeout || 30000;
		      let promise = new Promise(function (resolve, reject) {
		        // 向请求队列中添加对象
		        softphone.rqqueue[softphone.ctirefid.toString()] = {
		          // 超时检测定时器
		          timer: null,
		          method : method,
		          msg: request,
			        options: options,
		          resolve: resolve,
		          reject: reject
						};
		        softphone.checkTimedOut(softphone.ctirefid, timeout);

		        softphone.logmsg("Begin send request " + method + ": " + request);
		        softphone.websocket.send(request);
					  softphone.logmsg("msg sent");
					  softphone.OnSendMessage(request);
					});
		      return promise;
		    } else {
	        softphone.logmsg("Begin send request " + method + ": " + request);
	        softphone.websocket.send(request);
				  softphone.logmsg("msg sent");
				  softphone.OnSendMessage(request);
		    }
		  };

			softphone.checkTimedOut = function (ctirefid, timeout) {
				let invoke = softphone.rqqueue[ctirefid];
				if (invoke) {
					invoke.timer = window.setTimeout(function () {
						softphone.logmsg("timeout - " + invoke.msg);
						if (invoke.options && invoke.options.timeoutfunc) {
							invoke.options.timeoutfunc();
						}
						// 发送超时消息
						const error = new Error(Error.INVOKE_TIMEOUT, {
							method: invoke.method
						});
            //if (invoke.reject) {
            //  invoke.reject(error);
            //}
						softphone.InternalOnError(error.message, error.code, error.name);
						// 删除请求队列中的对象
						delete softphone.rqqueue[ctirefid];
					}, timeout);
				}
			};

			softphone.stopCheckTimedOut = function (ctirefid) {
        var invoke = softphone.rqqueue[ctirefid];
        if (invoke && invoke.timer) {
            window.clearTimeout(invoke.timer);
            invoke.timer = 0;
        }
        delete softphone.rqqueue[ctirefid];
			};

			softphone.logmsg = function(msg) {
				$SC.addconsolelog("[wscti]"+msg);
			};

			adduserdata = function(userdatas, key, type, value) {
	      if(!userdatas) {
	        //userdatas = JSON.stringify({type : 5, value : {}});
	        userdatas = {};
	      }
	      if (typeof(userdatas)=='string') {
	        try {
			      var t_data = JSON.parse(userdatas);
			      t_data[key] = {
	            type : type,
	            value : value
	          }
			      return JSON.stringify(t_data);
	        } catch (err) {

	        }
	      } else {
	        userdatas[key] = {
            type : type,
            value : value
	        }
	        return userdatas;
	      }
	    };

			userdata2metauserdata = function(userdatas) {
	      //userdatas: JSON Object, JSON string, '|' and '=' splitted key-value string
	      if (userdatas) {
	        if (typeof(userdatas) == 'object') {
	          var ud = {};
	          for (var v in userdatas) {
	            if (typeof(userdatas[v])!='object') {
	              ud[v] = {type: 3, value: userdatas[v]};
	            } else {
	              ud[v] = userdatas[v];
	            }
	          }
	          return ud;
	        }
		      try{
		        var t_datas = JSON.parse(userdatas);
			      return userdatas;
		      } catch(err) {
	          var t_data1 = userdatas.split("\|");
	          var t_data = {};
	          //for (var onedata in t_data1){
	          for (var i=0; i < t_data1.length; i++) {
	            var onedata = t_data1[i];
	            var n = onedata.indexOf("=");
	            if (n >= 0) {
	              t_data[onedata.substr(0, n)] = {"value" : onedata.substr(n+1), "type" : 3};
	            }
	          }
	          //return JSON.stringify(t_data);
	          return t_data;
		      }
	      }
	    };

			/*
	     * checkuudata: if no uu_data then return with no process, if uu_data then process it
	     * if no uu_data(same for raw_data, rawdata), return with no process
	     *
	     */
			checkuudata = function(userdatas) {
	      try {
	        var bvalue = false;
	        var uud = userdatas['uu_data'];
	        var uuds = '';
	        if (!uud) {
	          uud = userdatas['raw_data'];
	        }
	        if (!uud) {
	          uud = userdatas['rawdata'];
	        }
	        if (!uud) {
	          return userdatas;
	        } else {
	          var uudo;
	          var uuds = '';
	          if (typeof(uud) == 'object') {
	            if (uud.hasOwnProperty('value')) {
	              uud = uud.value;
	              bvalue = true;
	            }
	          }
	          if (typeof(uud) == 'object') {
	            uudo = uud;
	          } else {
	            try {
	              uudo = JSON.parse(uud);
	            } catch (err) {
	              if (keyvaluesplit && keyvaluesplit != '=' && (typeof(uud) == 'string')) {
	                uud = uud.replace(/=/g, keyvaluesplit);
	                if (bvalue) {
									userdatas.uu_data = {type: 3, value: uud};
								} else {
									userdatas.uu_data = uud;
								}
							}
	              return userdatas;
	            }
	          }
	          if (typeof(uudo) == "object") {
		          for (var v in uudo) {
		            uuds = uuds + '|' + v + keyvaluesplit + uudo[v];
		          }
		          if (uuds) {
			          uuds = uuds.substr(1);
		          } else {
		            uuds = uud;
		          }
	          } else {
	            uuds = uud;
	          }
	          userdatas.uu_data = {type: 3, value: uuds};
	          //userdatas.uu_data = uuds;
	          return userdatas;
	        }
	      } catch (err) {
	        return userdatas;
	      }
	    };

			getuserdatabykey = function(userdatas, key) {
	      if (!userdatas) {
	        return '';
	      }
	      if (typeof(userdatas)=='object') {
					for (var vkey in userdatas) {
						if (vkey.toLowerCase() == key.toLowerCase()) {
							if (userdatas[vkey].hasOwnProperty('value')) {
								return userdatas[vkey].value;
							} else {
								return userdatas[vkey];
							}

						}
					}
	      }
	      try {
		      var t_data = JSON.parse(userdatas);
		      if (t_data) {
		        return t_data[key].value;
		      }
	      } catch (err) {

	      }
	    };

			removeuserdatabykey = function(userdatas, key) {
	      if (typeof(userdatas) == 'object') {
	        delete userdatas[key];
	        return JSON.stringify(userdatas);
	      }
	      try {
		      var t_data = JSON.parse(userdatas);
		      if (t_data) {
		        if (t_data[key]) {
		          delete t_data[key];
		        }
		        return JSON.stringify(t_data);
		      }
		    } catch (err) {

		    }
	    };

			processuui = function(datas) {
        try {
          if (datas.userdata && datas.uui) {
            var t_userdata = datas.userdata.value;
	          var t_uui = datas.uui.value;
	          if (t_uui.indexOf('=') == -1) {
	            t_userdata = adduserdata(t_userdata, 'rawdata', 3, t_uui);
	          }

	          var t_uui_ar = t_uui.split("\|");
	          for (var i=0; i<t_uui_ar.length; i++) {
							var t_uui_1 = t_uui_ar[i].split(keyvaluesplit);
	            if (t_uui_1.length==2) {
	              t_userdata = adduserdata(t_userdata, t_uui_1[0], 3, t_uui_1[1]);
	              if (t_uui_1[0] == 'uui') {
	                t_userdata = adduserdata(t_userdata, 'rawdata', 3, t_uui_1[1]);
	              }
	            }
	          }

	          datas.userdata = {type: 5, value: t_userdata};
	          console.log('[testtest] processuuid return 1');
	          return 1;
	        }
	        return 0;
	      } catch (err) {
	        return -1;
	      }
	    };

			_onmessage = function(evt, opt) {
	      $SC.addconsolelog("[wscti]receive: " + evt.data);
        if (f_clearcalls) {
          $SC.addconsolelog("[wscti]f_clearcalls = " + f_clearcalls);
        }
	      var internaluse = false;
	      var bchanged = false;
        var datas = JSON.parse(evt.data);
        var refid = datas.ctirefid;
        if (refid) {
          refid = refid.value;
          var invoke = softphone.rqqueue[refid];
          if (invoke) {
            // 清除超时检测定时器
            softphone.stopCheckTimedOut(refid);
            if (invoke.options) {
              internaluse = invoke.options.internaluse;
            }
            if (datas.event.value == $CTI_CONST.CTI_MSG.EVT_ERROR) {
              if (datas.errorcode && datas.errorcode.value == "12") {
                if (invoke.method === "getcurrentagent") {
									var error = new Error(Error.INVALID_AGENT_ID, {agentId: softphone.agentid});
								} else {
									var error = new Error(Error.INVALID_DEVICE_ID, {deviceId: datas.dn.value})
								}
							} else {
                var errorcode = datas.errorcode.value;
                var error;
                if (errrorcode == -999) {
                  var curragent;
                  if (datas.currentagent) {
                    curragent = datas.currentagent.value;
									}
                  error = new Error(Error.EXIST_DEVICE_LOGIN, {agentId: curragent || ""});
								} else {
									error = new Error(Error.REQUEST_FAIL_CTIMSG, {
										method: invoke.method,
										errorcode: errorcode,
										data: evt.data
									});
								}
							}
              softphone.InternalOnError(error.message, error.code, error.name);
							if (invoke.method == 'agentlogout') {
								softphone.queryagentstate(softphone.dn, softphone.agentid, undefined, {timeout: 5000, internaluse: true})
									.then(function(e) {
										if (e.event.value == $CTI_CONST.CTI_MSG.EVT_AGENTLOGOUT) {
											$SC.addconsolelog('[wscti]internal queryagentstate got agentstate AgentLogout');
											//softphone.websocket.close();
											softphone.closewebsocket('EVT_AGENTLOGOUT');
										}
									}, function(e) {
										$SC.addconsolelog('[wscti]internal queryagentstate fail', e);
										//softphone.websocket.close();
										softphone.closewebsocket('queryagentstate fail');
									})
							}
            } else {
              invoke.resolve(datas);
            }
					}
				};
        for (vinv in softphone.rqqueue) {
          var invoke = softphone.rqqueue[vinv];
          if (invoke.options && invoke.options.succevents) {
            for (var i = 0; i < invoke.options.succevents.length; i++) {
              if (invoke.options.succevents[i] == datas.event.value) {
                softphone.stopCheckTimedOut(vinv);
                invoke.resolve(datas);
							}
						}
					}
          if (invoke.options && invoke.options.failevents) {
            for (var i = 0; i < invoke.options.failevents.length; i++) {
              if (invoke.options.failevents[i] == datas.event.value) {
                softphone.stopCheckTimedOut(vinv);
                var error = new Error(Error.REQUEST_FAIL_CTIMSG, {
                  method: invoke.method,
                  errorcode: datas.event.value,
                  datas: datas
								});
                softphone.InternalOnError(error.message, error.code, error.name);
								break;
							}
						}
					}
				};

        var m_ucid = '';
        switch(parseInt(datas.event.value)){
          case $CTI_CONST.CTI_MSG.EVT_RINGING:		//1
            if (f_clearcalls) {
              $SC.addconsolelog("[wscti]clear f_clearcalls from " + f_clearcalls + " by EVT_RINGING");
              f_clearcalls = 0;
						};
					case $CTI_CONST.CTI_MSG.EVT_DATAUPDATED: 	//74
          case $CTI_CONST.CTI_MSG.EVT_DIALING:		//20
          case $CTI_CONST.CTI_MSG.EVT_ESTABLISH:		//2
					case 52:									//EVT_TREATMENTAPPLIED=52;
					case $CTI_CONST.CTI_MSG.EVT_RINGBACK:
          case $CTI_CONST.CTI_MSG.EVT_HELD:			//6
            if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_HELD && datas.holdingdevice && datas.holdingdevice.value != softphone.dn) {
              $SC.addconsolelog("[wscti]EVT_HELD ignored for holdingdevice = " + datas.holdingdevice.value);
              opt.ignoreit = 1;
              return;
						}
          case $CTI_CONST.CTI_MSG.EVT_CONFERENCED:
          case $CTI_CONST.CTI_MSG.EVT_RETRIEVED:		//7
            if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_RETRIEVED && datas.retrievingdevice && datas.retrievingdevice.value != softphone.dn) {
              $SC.addconsolelog("[wscti]EVT_RETRIEVED ignored for retrievingdevice = " + datas.retrievingdevice.value);
              opt.ignoreit = 1;
              return;
            }
          case $CTI_CONST.CTI_MSG.EVT_RELEASED:
            if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_RELEASED && $SC.CallInfo.CallState2 == 0) {
              $SC.addconsolelog("[wscti]EVT_RELEASED ignored for no calls, maybe duplicated EVT_RELEASED or unexpected call released privately, f_clearcalls = " + f_clearcalls + ", clear f_clearcalls if needed");
              f_clearcalls = 0;
              opt.ignoreit = 1;
              return;
						}
          case $CTI_CONST.CTI_MSG.EVT_NETWORKREACHED:
            if (processuui(datas) == 1) {
              console.log('[testtest] userdatas bchanged = true');
              bchanged = true;
            }
            if (datas.ucid) {
              m_ucid = datas.ucid.value;
            };
            if (m_ucid) {
              var t_userdata = datas.userdata;
              if (t_userdata) {
                t_userdata = t_userdata.value;
              }
              t_userdata = adduserdata(t_userdata, 'ucid', 3, m_ucid);
              datas.userdata = {type: 5, value: t_userdata};
              bchanged = true;
            }

            if (!m_Calllist) {
              m_Calllist = {};
            }

            var conn = '',
                conn1 = '',
                calls = "",
                callids = "";

            if (datas.connectionid) {
              conn = datas.connectionid.value;
            } else if (datas.callid) {
              conn = datas.callid.value;
            }

            if (!conn) {
              if (bchanged) {
                $SC.addconsolelog('[wscti][testtest] with no connectionid, set evt.data2 = ' + JSON.stringify(datas));
                evt.data2 = JSON.stringify(datas);
                $SC.addconsolelog('[wscti][testtest] now evt.data2 = ' + evt.data2);
              }
              return;
            }
            if (datas.prevconnectionid) {
              conn1 = datas.prevconnectionid.value;
            } else {
              //conn1 = m_Calllist[conn].prevconnectionid;
            }

            if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_RELEASED) {
              if (!m_Calllist[conn] && !$SC.CallInfo.m_Calllist[conn]) {
								$SC.addconsolelog("[wscti]EVT_RETRIEVED ignored for unknown callid = " + conn);
								opt.ignoreit = 1;
								return;
							}
	            delete m_Calllist[conn];
	            if (conn1) {
	              if (m_Calllist[conn1]) {
	                m_Calllist[conn1].prevconnectionid = '';
	              }
	            }
	            for (var x in $SC.CallInfo.m_Calllist) {
	              calls = calls + '('+ x + ','+ $SC.CallInfo.m_Calllist[x].callstate + ')'
	              callids = callids + "+" + x;
	            }
	            if (f_clearcalls) {
	              $SC.addconsolelog("[wscti]f_clearcalls = " + f_clearcalls + ", f_clearcalls minus 1, calls = " + calls);
	              if (f_clearcalls > 0) {
	                f_clearcalls = f_clearcalls - 1;
	              }
	              if (calls) {
	              } else {
	                f_errorclearcalls = false;
	              }
	            }
	          } else if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_RINGBACK || parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_NETWORKREACHED) {
	            if (!conn1 && m_Calllist[conn].prevconnectionid) {
	              conn1 = m_Calllist[conn].prevconnectionid.value;
	            }
	            $SC.addconsolelog("[wscti]EVT_RINGBACK or EVT_NETWORKREACHED, conn = " + conn + ", conn1 = " + conn1);
						} else {
	            m_Calllist[conn] = datas;
	            if (conn1) {
	              if (m_Calllist[conn1]) {
	                m_Calllist[conn1].prevconnectionid = conn;
	              }
	            }
	            $SC.addconsolelog("[wscti]conn = " + conn + ", conn1 = " + conn1);
	          }

	          if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_DIALING) {
	            if (conn1 && (conn1 == conn_autocomplete || conn == conn_autocomplete)) {
	              if (f_autocomplete == 'completetransferwhendialing') {
	                softphone.completetransfer(conn, conn1);
									f_autocomplete = '';
									f_errorclearcalls = true;
	              } else if (f_autocomplete == 'completeconferencewhendialing') {
	                softphone.completeconference(conn, conn1);
	                f_autocomplete = '';
	              } if (f_autocomplete == 'completetransferwhenrb') {
	                setTimeout(function(){
								if (f_autocomplete == 'completetransferwhenrb') {
									softphone.completetransfer(conn, conn1);
									f_autocomplete = '';
									f_errorclearcalls = true;
								}
							}, 1000)
						}
	        }
	        if (f_clearcalls && !datas.prevconnectionid) {
	          $SC.addconsolelog("[wscti]clear f_clearcalls from " + f_clearcalls + " after releasecall for unexpected EVT_DIALING " + conn);
	          f_clearcalls = 0;
	          m_request_comments = 'releasecall for unexpected EVT_DIALING';
	          softphone.releasecall(conn);
						opt.ignoreit = 1;
						return;
	        }
        } else if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_NETWORKREACHED) {
          if (conn1 && (conn1 == conn_autocomplete || conn == conn_autocomplete)) {
            if ((f_autocomplete == 'completetransferwhendialing')||(f_autocomplete == 'completetransferwhennr')) {
              softphone.completetransfer(conn, conn1);
              f_autocomplete = '';
              f_errorclearcalls = true;
            } else if ((f_autocomplete == 'completeconferencewhendialing')||(f_autocomplete == 'completeconferencewhennr')) {
              softphone.completeconference(conn, conn1);
              f_autocomplete = '';
            }
          }
        } else if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_RINGBACK) {
          if (conn1 && (conn1 == conn_autocomplete || conn == conn_autocomplete)) {
            if ((f_autocomplete == 'completetransferwhendialing')||(f_autocomplete == 'completetransferwhennr')||(f_autocomplete == 'completetransferwhenrb')) {
              softphone.completetransfer(conn, conn1);
              f_autocomplete = '';
              f_errorclearcalls = true;
            } else if ((f_autocomplete == 'completeconferencewhendialing')||(f_autocomplete == 'completeconferencewhennr')||(f_autocomplete == 'completeconferencewhenrb')) {
              softphone.completeconference(conn, conn1);
              f_autocomplete = '';
            }

          }
        } else if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_ESTABLISH) {
          if (conn1 && (conn1 == conn_autocomplete || conn == conn_autocomplete)) {
            if ((f_autocomplete == 'completetransferwhendialing')||(f_autocomplete == 'completetransferwhennr')||(f_autocomplete == 'completetransferwhenrb')||(f_autocomplete == 'completetransferwhenestablish')) {
              softphone.completetransfer(conn, conn1);
              f_autocomplete = '';
              f_errorclearcalls = true;
            } else if ((f_autocomplete == 'completeconferencewhendialing')||(f_autocomplete == 'completeconferencewhennr')||(f_autocomplete == 'completeconferencewhenrb')||(f_autocomplete == 'completeconferencewhenestablish')) {
              softphone.completeconference(conn, conn1);
              f_autocomplete = '';
            }
          }
        }  else if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_RELEASED) {
          //if (conn1 && f_autocomplete.indexOf('completetransfer')>=0) {
          if (f_autocomplete.indexOf('completetransfer')>=0) {
            f_autocomplete = '';
            if (callids = "+" + conn) {
              $SC.addconsolelog("[wscti]no need clearcalls(), and no auto completetransfer");
            } else {
              $SC.addconsolelog("[wscti]clearcalls(), and no auto completetransfer")
              m_request_comments = 'clearcalls() for f_autocomplete = ' + f_autocomplete;
              softphone.clearcalls();
            }
          }
        }
        break;
            case $CTI_CONST.CTI_MSG.EVT_AGENTLOGOUT:
              if (internaluse) {
                evt.data2 = {internaluse: true};
              } else {
                softphone.registereddn = '';
                //softphone.websocket.close();
                softphone.closewebsocket('EVT_AGENTLOGOUT');
              }
              if (f_clearcalls) {
                $SC.addconsolelog("[wscti]clear f_clearcalls from " + f_clearcalls);
              }
              try {
								for (vinv in softphone.rqqueue) {
									var invoke = softphone.rqqueue[vinv];
									if (invoke) {
										softphone.logmsg("remove request waiting: " + invoke.method);
									}
									softphone.stopCheckTimedOut(vinv);
								}
							} catch (e) {

							}
              break;
            case $CTI_CONST.CTI_MSG.EVT_REGISTERED:
              softphone.registereddn = datas.thisdn;
              if (f_clearcalls) {
                $SC.addconsolelog("[wscti]clear f_clearcalls from " + f_clearcalls);
              }
              break;
            case $CTI_CONST.CTI_MSG.EVT_UNREGISTERED:
              softphone.registereddn = '';
              break;
            case $CTI_CONST.CTI_MSG.EVT_AGENTREADY:
            case $CTI_CONST.CTI_MSG.EVT_AGENTNOTREADY:
              if (internaluse) {
                evt.data2 = {internaluse: true};
              }
              if (!m_timer_login) {
                m_timer_login = setInterval(function(){
                  if (softphone.registereddn) {
                    softphone.queryagentstate(softphone.dn, softphone.agentid, undefined, {timeout: 5000, internaluse: true})
                  .then(function(e) {
                    if (e.event.value == $CTI_CONST.CTI_MSG.EVT_AGENTLOGOUT) {
                      $SC.addconsolelog('[wscti]internal queryagentstate got agentstate AgentLogout');
                      //softphone.websocket.close();
			                softphone.closewebsocket('EVT_AGENTLOGOUT');
                    }
                  }, function(e) {
                  })
                  } else {
                    clearInterval(m_timer_login);
                    m_timer_login = 0;
                  }
                }, 300000);
              }
              break;
            case $CTI_CONST.CTI_MSG.EVT_ERROR:
					    if (datas.errorcode) {
                switch (parseInt(datas.errorcode.value)) {
                  case 12:	//INVALID_CSTA_DEVICE_IDENTIFIER = 12,
										datas.errordesc = {type: 3, value: $SC.lang("common.err.invaliddeviceplus", "无效的分机号码：") + datas.thisdn.value};
                    evt.data2 = JSON.stringify(datas);
                    break;
                  case 33:	//RESOURCE_BUSY
                    datas.errordesc = {type: 3, value: $SC.lang("common.err.deviceincall", "分机在通话中：") + datas.thisdn.value};
                    evt.data2 = JSON.stringify(datas);
                    break;
                  case 1:		//GENERIC_OPERATION = 1,
                    datas.errordesc = {type: 3, value: $SC.lang("common.err.errorcodeplus", "错误代码：") + datas.errorcode.value + $SC.lang("common.err.possibledevicenotregisteredpre", "，可能是分机未注册。")};
                    evt.data2 = JSON.stringify(datas);
                    break;
									case -999:	//DN 60995 already be monitored in control mode by client 1
										var curragent;
										if (datas.currentagent) {
											curragent = datas.currentagent.value;
										}
										var error = new Error(Error.EXIST_DEVICE_LOGIN, {agentId: curragent || ""});
										datas.errordesc = error.message;
										evt.datas = JSON.stringify(datas);
										break;
								}
							}
              if (internaluse) {
                if (!evt.data2) {
                  evt.data2 = {internaluse: true};
                } else {
                  evt.data2.internaluse = true;
                }
              }
              if (f_errorclearcalls && f_clearcalls) {
                $SC.addconsolelog("[wscti]mutetransfer with EVT_ERROR, f_clearcalls = " + f_clearcalls);
								m_request_comments = "clearcalls() for mutetransfer with EVT_ERROR";
                softphone.clearcalls();
                f_errorclearcalls = false;
              }
          }
	        if (bchanged) {
	          $SC.addconsolelog('[wscti][testtest] set evt.data2 = ' + JSON.stringify(datas));
	          evt.data2 = JSON.stringify(datas);
	          $SC.addconsolelog('[wscti][testtest] now evt.data2 = ' + evt.data2);
	        }
				};

			return softphone;
		}
	};
	return ELITEWSCTIClient.createNew();
});
